ActiveMQからAmazon MQへの移行はどれほど簡単なのか #reinvent
こんにちは。サービスグループの武田です。
re:Invent 2017も盛況のうちに終わり、弊社もまた日常が戻ってきました。
今回の発表もさまざまなものがありましたが、その中にActiveMQのフルマネージドサービスがありました。その名もAmazon MQ。さっそくいくつか記事も上がっていましたね。
AWSにはもともとAmazon SQSというキューイングサービスや、Amazon SNSというトピックサービスがありました。ユースケースとしては、Amazon MQは既存の環境からの移行、SQSやSNSは新規のアプリケーション開発に使うとよいようです。
今回は既存のActiveMQを使用しているアプリケーションが、どれほど簡単にAmazon MQに移行できるのか気になったので試してみました。
環境
$ docker --version Docker version 17.09.0-ce, build afdb6d4 $ gradle --version ------------------------------------------------------------ Gradle 4.4 ------------------------------------------------------------ Build time: 2017-12-06 09:05:06 UTC Revision: cf7821a6f79f8e2a598df21780e3ff7ce8db2b82 Groovy: 2.4.12 Ant: Apache Ant(TM) version 1.9.9 compiled on February 2 2017 JVM: 1.8.0_144 (Oracle Corporation 25.144-b01) OS: Mac OS X 10.12.6 x86_64
ActiveMQの準備
まずは移行前の環境をシミュレートするために、ローカルにActiveMQの環境を用意します。
今回はDocker Compose
でさくっと用意しました。
$ mkdir /path/to/activemq && cd $_ $ vim docker-compose.yml $ docker-compose up -d
activemq: image: webcenter/activemq:latest ports: - 8161:8161 - 61616:61616 - 61613:61613 environment: ACTIVEMQ_NAME: amq ACTIVEMQ_REMOVE_DEFAULT_ACCOUNT: 'True' ACTIVEMQ_ADMIN_LOGIN: admin ACTIVEMQ_ADMIN_PASSWORD: admin volumes: - ./activemq/data:/data/activemq - ./activemq/log:/var/log/activemq
起動できたらブラウザから管理コンソールにアクセスしてみます。URLはhttp://localhost:8161/
となっています。
Gradleを実行する
GradleでJavaを実行するための準備と、ActiveMQへの接続に必要なライブラリの依存関係も定義します。
$ mkdir java cd $_ $ mkdir -p src/main/{java/jp/cm/example,resources} $ vim build.gradle $ vim src/main/java/jp/cm/example/Main.java
apply plugin: 'application' mainClassName = 'jp.cm.example.Main' repositories { mavenCentral() } ext { slf4jVersion = '1.7.25' log4jVersion = '2.10.0' activemqVersion = '5.15.2' } dependencies { compile "org.slf4j:slf4j-log4j12:$slf4jVersion" compile "org.apache.logging.log4j:log4j-core:$log4jVersion" compile "org.apache.activemq:activemq-client:$activemqVersion" }
package jp.cm.example; public class Main { public static void main(String[] args) { System.out.println("Hello, Amazon MQ!"); } }
Main.java
はとりあえず動作確認用に、テキストを出力するだけです。 ファイルを用意できたらタスクを実行してみます。
$ gradle run > Task :run Hello, Amazon MQ! BUILD SUCCESSFUL in 8s 2 actionable tasks: 2 executed
JavaからActiveMQに接続
次にJNDIとLog4jのプロパティファイルを作成します。
$ vim src/main/resources/jndi.properties $ vim src/main/resources/log4j.properties
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory java.naming.provider.url = tcp://localhost:61616 queue.DevQueue = queue-sample-dev
log4j.rootLogger=INFO, ROOT log4j.appender.ROOT=org.apache.log4j.ConsoleAppender log4j.appender.ROOT.layout=org.apache.log4j.PatternLayout log4j.appender.ROOT.layout.ConversionPattern=%-5p - %m%n log4j.appender.null=org.apache.log4j.varia.NullAppender
いよいよ先ほど作成したMain.java
を書き換え、ActiveMQに接続してみましょう。
プログラムはいたってシンプルで、キューにメッセージを送信するだけです。実行は先ほどと同じコマンドです。
$ vim src/main/java/jp/cm/example/Main.java
package jp.cm.example; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.Context; import javax.naming.InitialContext; public class Main { private static final String QUEUE_NAME = "DevQueue"; private static final String MESSAGE_BODY = "Test Message"; public static void main(String[] args) throws Exception { Context context = new InitialContext(); System.out.println(context.getEnvironment()); ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("ConnectionFactory"); Connection connection = connectionFactory.createConnection(); connection.start(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination destination = (Destination) context.lookup(QUEUE_NAME); MessageProducer producer = session.createProducer(destination); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); TextMessage message = session.createTextMessage(MESSAGE_BODY); producer.send(message); System.out.println("Send message id: " + message.getJMSMessageID()); session.close(); connection.close(); } }
$ gradle run > Task :run {java.naming.provider.url=tcp://localhost:61616, java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory, queue.DevQueue=queue-sample-dev} Send message id: ID:HL00235-58633-1512844370717-1:1:1:1:1 BUILD SUCCESSFUL in 1s 3 actionable tasks: 2 executed, 1 up-to-date
ブラウザから結果を確認してみます。
docker-compose.yml
で指定しているユーザー名とパスワードを指定します。
たしかにキューに入ってますね!
Amazon MQでブローカーを作成
Amazon MQはまだ東京リージョンに来ていないため、今回はバージニア北部で作成しました。
また8162
番ポートと61617
番ポートにアクセスできるよう、セキュリティグループを設定する必要があります。
すべてデフォルトで作成した後にセキュリティグループをアタッチしようとしたんですが、ブローカー作成後にアタッチする方法がわかりませんでした 。先にセキュリティグループを作成しておき、作成時にアタッチするのが無難そうです。
スクリーンショットの時間を見ると、約13分ほどかかっていました。
ブローカー名を選択すると、詳細画面に移ります。
OpenWireのエンドポイントはこのあと使うため、メモしておきましょう。
ブラウザからhttps://b-0f872849-a819-48cf-8155-9c4879bdf35a-1.mq.us-east-1.amazonaws.com:8162/
にアクセスするとAmazon MQの管理コンソールにアクセスできます。
JavaからAmazon MQに接続
接続先の切り替えは、jndi.properties
を書き換えるだけです。ただし、先ほどのローカルと異なり、ユーザー名とパスワードによる認証が必要です。java.naming.provider.url
は作成したブローカーの、OpenWire
のエンドポイント。userName
とpassword
はブローカーを作成するときに指定したものとしてください。
$ cp src/main/resources/jndi.properties{,.local} $ vim src/main/resources/jndi.properties
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory java.naming.provider.url = ssl://b-0f872849-a819-48cf-8155-9c4879bdf35a-1.mq.us-east-1.amazonaws.com:61617 queue.DevQueue = queue-sample-dev userName = takeda.takashi password = ************
実行方法は変わらず、gradle run
を実行します。
$ gradle run Starting a Gradle Daemon (subsequent builds will be faster) > Task :run {java.naming.provider.url=ssl://b-0f872849-a819-48cf-8155-9c4879bdf35a-1.mq.us-east-1.amazonaws.com:61617, java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory, password=************, queue.DevQueue=queue-sample-dev, userName=takeda.takashi} Send message id: ID:HL00235-59715-1512848178473-1:1:1:1:1 BUILD SUCCESSFUL in 6s 3 actionable tasks: 2 executed, 1 up-to-date
ブラウザから結果を確認してみます。
管理コンソールの操作方法は先ほどと同じです。
キューに入っていることが確認できました!
まとめ
非常にシンプルなプログラムでしたが、JNDIのプロバイダを切り替えるだけで、既存のプログラムからAmazon MQへの接続が確認できました。
今回はプロデューサーのプログラムのみでしたが、コンシューマーも同じように切り替えることが可能です。
SQSやSNSへの移行は見送っていた方も、Amazon MQへの移行を検討してみてはいかがでしょうか。